/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_count.h

	$Header: /game/creature_count.h $

	$NoKeywords: $

 ************************************************************************/
#ifndef CREATURE_ARRAY_H_INCLUDED
#define CREATURE_ARRAY_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#pragma warning( disable: 4786 )

#include <list>
#include "adv_map_point.h"
#include "adv_object_map_info.h"
#include "creature_stack.h"
#include "patrol_type.h"
#include "player_color.h"
#include "uncopyable.h"
#include "sized_int_types.h"
#include "town_type.h"

class	t_abstract_town;
class   t_abstract_grail_data_source;
class	t_adventure_map;
class	t_ai_army_data_cache;
enum	t_ai_importance;
class	t_creature_array;
enum	t_direction;
enum	t_formation_type;
class	t_player;
enum	t_skill_mastery;
enum	t_town_building;
class	t_window;

class t_creature_array_list : public std::list<t_creature_array*>
{
};

// ------------------------------------------------------
// array of creatures and/or heroes
// ------------------------------------------------------
class t_creature_array : public virtual t_adv_object_map_info, public t_uncopyable
{
public:
	enum { k_size = 7 };
	typedef	t_counted_ptr< t_ai_army_data_cache > t_ai_data_cache_ptr;

	t_creature_array();
	explicit t_creature_array( t_creature_array* source ); // transfers contents
	virtual ~t_creature_array();

	t_creature_stack const* ai_get_most_powerful( float& value, float& total_value ) const;

	void					ai_start_turn();
	float					ai_value() const;
	float					ai_value_including_dead() const;
	float					ai_value_creatures(bool include_generalship = true) const;

	bool					add( t_creature_stack_ptr arg, int index = -1 );
	bool                    add( t_creature_type creature, int amount, int index = -1 ); // newly-created creatures
	bool                    add( t_artifact const& artifact );
	void					add_bonus( t_stat_type stat, int amount ); // always temporary
	void                    add_experience( int amount, t_window* parent = 0, bool 
											evenly = false );
	bool					add_move_bonus( int amount, 
		                                    t_qualified_adv_object_type const& object_type,
											int days );
	bool					can_add( t_creature_type creature ) const;
	bool					can_add_hero() const;
	virtual void			change_movement( int amount );
	void					check_hero_levels( bool show_dialogs = true );
	void					clear();
	void					clear( int slot );
	virtual int				compute_scouting_range() const;
	void                    consolidate(); // merge all duplicate stacks.
	void					copy_extra_properties( t_creature_array const& source );
	bool					empty() const;
	virtual void			expend_all_movement();
	virtual void			expend_most_movement( int max_remaining_movement );
	int                     find( t_hero const* hero ) const;
	int                     find( t_creature_type creature_type ) const;
	bool					is_alive() const;
	bool					is_aquatic() const;
	bool					is_full_army() const;
	virtual bool			is_graveyard() const;
	t_ai_army_data_cache*	get_ai_data_cache() const;
	t_skill_mastery			get_anti_stealth_level() const;
	t_hero const*			get_any_hero() const;
	t_hero*					get_any_hero();
	int						get_boat_movement() const;
	virtual t_town_type		get_boat_type () const;
	virtual t_creature_array* get_creature_array();
	int						get_empty_slot_count() const;
	int                     get_experience_value() const;
	int                     get_fastest_raw_move() const;
	t_formation_type		get_formation() const;
	virtual t_abstract_grail_data_source const & get_grail_data() const;
	int                     get_hero_count() const;
	t_ai_importance			get_importance() const;
	t_adv_map_point const&	get_initial_location() const;
	t_creature_stack &      get_leader();
	t_creature_stack const& get_leader() const;
	int						get_leader_index() const;
	int						get_living_hero_count() const;
	t_hero*					get_most_powerful_skill( t_skill_type skill );
	t_hero const*			get_most_powerful_skill( t_skill_type skill ) const;
	int						get_most_powerful_skill_power( t_skill_type skill ) const;
	int					    get_morale( t_town_type alignment ) const;
	int						get_move_cost( t_terrain_type terrain ) const;
	int						get_movement() const;
	virtual int             get_movement( bool sea_move ) const;
	int						get_movement( t_creature_stack const& stack ) const;
	int						get_movement( t_creature_stack const& stack, bool in_boat ) const;
	float					get_movement_modifier( t_creature_stack const& stack, bool in_boat ) const;
	int						get_max_movement() const;
	virtual int             get_max_movement( bool sea_move ) const;
	int						get_max_movement( t_creature_stack const& stack ) const;
	int						get_max_movement( t_creature_stack const& stack, bool in_boat ) const;
	int                     get_movement_bonus( bool sea_movement ) const;
	t_int8					get_patrol_radius() const;
	t_patrol_type			get_patrol_type() const;
	int						get_recruitment_discount() const;
	t_skill_mastery			get_skill( t_skill_type skill, t_hero** hero = 0 ) const;
	int						get_shortest_bonus( t_qualified_adv_object_type const& object_type ) const;
	t_skill_mastery			get_stealth_level() const;
	t_hero const*			get_strongest_hero() const;
	t_hero*					get_strongest_hero();
	t_hero const*			get_weakest_hero() const;
	t_hero*					get_weakest_hero();
	bool					has_seamans_hat() const;
	void					initialize();
	bool					is_in_patrol_radius( t_adv_map_point const& point ) const;
	void					learn_spells( t_town const* town );
	void					move_creatures_from( t_creature_array& arg );
	void					on_begin_turn();
	void					on_end_turn();
	bool                    preplacement( t_adventure_map& map, int pass, t_player* owner );
	void		            process_new_day( bool grow );
	bool					read( std::streambuf& stream );
	bool                    read_version( std::streambuf& stream, int version );
	bool                    read_from_map( std::streambuf& stream );
	void					read_postplacement( t_adventure_map & map );
	bool                    read_summary_from_map( std::streambuf& stream );
	void                    remove( int amount, int slot );
	virtual bool			select(); // select in adventure frame.  Returns false if not possible.
	void					set_ai_data_cache(t_ai_data_cache_ptr cache_ptr);
	void					set_formation( t_formation_type arg );
	void					set_importance( t_ai_importance importance );
	virtual void			set_in_combat( bool arg );
	void					set_initial_location(t_adv_map_point const& point);
	void					set_patrol_radius( t_int8 radius );
	void					set_patrol_type( t_patrol_type type );
	void                    swap( t_creature_array& other );
	void                    swap( t_creature_stack_ptr& stack, int slot );
	void					swap_creatures( t_creature_array& other );
	void					visit_town( t_abstract_town * town );
	bool                    write( std::streambuf& stream ) const;

	t_creature_stack const& operator[]( int arg ) const;
	t_creature_stack&		operator[]( int arg );
protected:
	t_hero const*			get_most_powerful_skill_const( t_skill_type skill ) const;
	int						get_move_bonus( bool in_boat ) const;
	float					get_move_multiplier( bool in_boat ) const;
	virtual void			post_change(void);
	
	t_ai_data_cache_ptr		m_ai_data_cache;
	t_ai_importance			m_ai_importance;
	t_creature_stack_ptr	m_data[k_size];
	t_formation_type		m_formation;
	t_adv_map_point			m_initial_location; // Point placed on map in editor. Valid only for armies placed in map editor
	t_patrol_type			m_patrol_type;
	t_int8					m_patrol_radius;
};

inline t_creature_stack const& t_creature_array::operator [] (int arg) const
{
	return *m_data[arg];
}

inline t_creature_stack& t_creature_array::operator [] (int arg)
{
	return *m_data[arg];
}

inline 	t_town_type t_creature_array::get_boat_type () const
{
	return k_town_none;
}

inline t_formation_type t_creature_array::get_formation() const
{
	return m_formation;
}

inline int t_creature_array::get_max_movement() const
{
	return get_max_movement( is_boat() );
}

inline int t_creature_array::get_max_movement( t_creature_stack const& stack, bool in_boat ) const
{
	return (int)(get_movement_modifier( stack, in_boat ) * stack.get_raw_adventure_movement());
}

inline int t_creature_array::get_max_movement( t_creature_stack const& stack ) const
{
	return get_max_movement( stack, is_boat() );
}

inline int t_creature_array::get_movement() const
{
	return get_movement( is_boat() );
}

inline int t_creature_array::get_movement( t_creature_stack const& stack, bool in_boat ) const
{
	return (int)(get_movement_modifier( stack, in_boat ) * stack.get_raw_adventure_movement_left());
}

inline int t_creature_array::get_movement( t_creature_stack const& stack ) const
{
	return get_movement( stack, is_boat() );
}

inline t_ai_importance t_creature_array::get_importance() const
{
	return m_ai_importance;
}

inline void t_creature_array::set_importance( t_ai_importance importance )
{
	m_ai_importance = importance;
}

// ------------------------------------------------------
// array of creatures and/or heroes
// find the "leader" - highest-level hero, or toughest creature.
// ------------------------------------------------------
inline t_creature_stack & t_creature_array::get_leader()
{
	return *m_data[get_leader_index()];
}

// ------------------------------------------------------
// array of creatures and/or heroes
// find the "leader" - highest-level hero, or toughest creature.
// ------------------------------------------------------
inline t_creature_stack const& t_creature_array::get_leader() const
{
	return *m_data[get_leader_index()];
}

inline t_hero* t_creature_array::get_most_powerful_skill( t_skill_type skill )
{
	return const_cast<t_hero*>(get_most_powerful_skill_const( skill ));
}


inline t_hero const* t_creature_array::get_most_powerful_skill( t_skill_type skill ) const
{
	return get_most_powerful_skill_const( skill );
}

inline void t_creature_array::swap( t_creature_stack_ptr& stack, int slot )
{
	std::swap( stack, m_data[slot] );
}

inline t_patrol_type t_creature_array::get_patrol_type() const
{
	return m_patrol_type;
}

inline t_int8 t_creature_array::get_patrol_radius() const
{
	return m_patrol_radius;
}

inline void t_creature_array::set_formation( t_formation_type arg )
{
	m_formation = arg;
}

// Free functions
bool can_combine( t_creature_array const & first, t_creature_array const & second );
void add_start_creature( t_creature_array& garrison, t_town_type town_type,
						 t_town_building building );

#endif // CREATURE_ARRAY_H_INCLUDED